package com.dlc.shop.api.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dlc.shop.bean.app.dto.MyOrderDto;
import com.dlc.shop.bean.app.dto.MyOrderItemDto;
import com.dlc.shop.bean.app.dto.OrderItemDto;
import com.dlc.shop.bean.app.dto.OrderShopDto;
import com.dlc.shop.bean.enums.*;
import com.dlc.shop.bean.event.FlowSystemTypeEnum;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.vo.OrderItemVO;
import com.dlc.shop.bean.vo.OrderWxDeliveryVO;
import com.dlc.shop.common.constants.PlatformInterventionStatus;
import com.dlc.shop.common.enums.PayType;
import com.dlc.shop.common.enums.SysTypeEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.i18n.I18nMessage;
import com.dlc.shop.common.response.ServerResponseEntity;
import com.dlc.shop.common.util.Arith;
import com.dlc.shop.common.util.BeanUtil;
import com.dlc.shop.common.util.PageParam;
import com.dlc.shop.config.WxConfig;
import com.dlc.shop.security.api.util.SecurityUtils;
import com.dlc.shop.security.common.util.AuthUserContext;
import com.dlc.shop.service.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author LGH
 */
@RestController
@RequestMapping("/p/myOrder")
@Tag(name = "我的订单接口")
@AllArgsConstructor
public class MyOrderController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final OrderService orderService;
    private final ProductService productService;
    private final SkuService skuService;
    private final MyOrderService myOrderService;
    private final OrderItemService orderItemService;
    private final OrderRefundService orderRefundService;
    private final OrderVirtualInfoService orderVirtualInfoService;
    private final WxConfig wxConfig;
    private final PayInfoService payInfoService;

    @GetMapping("/orderDetail")
    @Operation(summary = "订单详情信息" , description = "根据订单号获取订单详情信息")
    @Parameter(name = "orderNumbers", description = "订单号（多个订单以，相隔）" , required = true)
    public ServerResponseEntity<OrderShopDto> orderDetail(@RequestParam(value = "orderNumber") String orderNumber) {
        String userId = SecurityUtils.getUser().getUserId();
        Long stationId = SecurityUtils.getUser().getStationId();
        if (Objects.equals(AuthUserContext.get().getSysType(), SysTypeEnum.STATION)) {
            userId = null;
        }
        OrderShopDto orderShopDto = orderService.orderDetail(orderNumber, userId, stationId);

        if (Objects.isNull(orderShopDto)) {
            // 订单不存在
            throw new YamiShopBindException("yami.order.no.exist");
        }
        // 返回拼团/秒杀优惠扣除店铺改价金额和平台优惠金额
        orderShopDto.setShopAmount(Arith.sub(Arith.sub(orderShopDto.getReduceAmount(), orderShopDto.getPlatformAmount()), orderShopDto.getShopChangeFreeAmount()));
        // 插入退款和虚拟商品信息
        refundAndVirtualInfo(orderShopDto, stationId);
        return ServerResponseEntity.success(orderShopDto);
    }

    @GetMapping("/myOrder")
    @Operation(summary = "订单列表信息" , description = "根据订单状态获取订单列表信息，状态为0时获取所有订单")
    @Parameter(name = "status", description = "订单状态 0:获取所有订单 1:待付款 2:待发货 3:待收货 4:待评价 5:成功 6:失败 7待成团" )
    public ServerResponseEntity<IPage<MyOrderDto>> myOrder(@RequestParam(value = "status") Integer status, @RequestParam(value = "prodName", required = false ) String prodName, PageParam<MyOrderDto> page) {
        String userId = SecurityUtils.getUser().getUserId();
        IPage<MyOrderDto> myOrderDtoIpage = myOrderService.pageMyOrderByUserIdAndStatus(page, userId, status, prodName);
        return ServerResponseEntity.success(myOrderDtoIpage);
    }

    @GetMapping("/myOrderSearch")
    @Operation(summary = "订单列表信息查询" , description = "根据订单编号或者订单中商品名称搜索")
    @Parameters({
            @Parameter(name = "status", description = "订单状态 1:待付款 2:待发货 3:待收货 4:待评价 5:成功 6:失败" ),
            @Parameter(name = "orderMold", description = "订单类别 0.实物商品订单 1. 虚拟商品订单" ),
            @Parameter(name = "orderName", description = "订单编号或者订单中商品名称" ),
            @Parameter(name = "orderTimeStatus", description = "0全部订单 1最近七天 2最近三个月 3三个月之前 订单" ),
            @Parameter(name = "orderType", description = "0全部订单 1拼团订单 2秒杀订单 3积分订单" ),
            @Parameter(name = "orderNumber", description = "订单编号" ),
            @Parameter(name = "shopId", description = "店铺id" )
    })
    public ServerResponseEntity<IPage<MyOrderDto>> myOrderSearch(@RequestParam(value = "status") Integer status,
                                                           @RequestParam(value = "orderName") String orderName,
                                                           @RequestParam(value = "orderTimeStatus", required = false) Integer orderTimeStatus,
                                                           @RequestParam(value = "orderType", required = false) Integer orderType,
                                                           @RequestParam(value = "orderMold") Integer orderMold,
                                                           @RequestParam(value = "orderNumber") String orderNumber,
                                                           @RequestParam(value = "shopId", required = false) Long shopId,
                                                           PageParam<MyOrderDto> page) {
        String userId = SecurityUtils.getUser().getUserId();
        IPage<MyOrderDto> myOrderDtoIpage = myOrderService.pageMyOrderByParams(page, userId, status, orderName, orderTimeStatus, orderType, orderNumber, shopId,orderMold);
        return ServerResponseEntity.success(myOrderDtoIpage);
    }

    @GetMapping("/getOrderItem")
    @Operation(summary = "获取订单项信息" , description = "根据订单项Id获取订单项信息")
    @Parameter(name = "orderItemId", description = "订单项Id" )
    public ServerResponseEntity<OrderItemVO> getOrderItem(@RequestParam(value = "orderItemId") Long orderItemId) {
        OrderItem orderItem = orderItemService.getByIdI18n(orderItemId);
        orderItem.setPic(orderItem.getPic());
        Order one = orderService.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber,orderItem.getOrderNumber()));
        OrderItemVO orderItemVO = BeanUtil.map(orderItem, OrderItemVO.class);
        orderItemVO.setPayDate(one.getPayTime());
        return ServerResponseEntity.success(orderItemVO);
    }

    @GetMapping("/getOrderItems")
    @Operation(summary = "获取订单项信息" , description = "根据订单编号orderNumber获取订单项信息")
    @Parameter(name = "orderNumber", description = "订单编号" )
    public ServerResponseEntity<List<OrderItem>> getOrderItems(@RequestParam(value = "orderNumber") String orderNumber) {
        List<OrderItem> orderItems = orderItemService.listAndPayTimeByOrderNumber(orderNumber);
        return ServerResponseEntity.success(orderItems);
    }

    @GetMapping("/myOrderComment")
    @Operation(summary = "订单评价列表接口" , description = "根据订单评价状态获取订单列表信息")
    public ServerResponseEntity<IPage<MyOrderDto>> myOrderComment(PageParam<MyOrderDto> page) {
        String userId = SecurityUtils.getUser().getUserId();
        IPage<MyOrderDto>  myOrderDtoIpage = myOrderService.myOrderComment(page, userId);
        return ServerResponseEntity.success(myOrderDtoIpage);
    }

    @GetMapping("/myOrderItemsComment")
    @Operation(summary = "订单项评价列表接口" , description = "根据订单评价状态获取订单列表信息")
    @Parameter(name = "commStatus", description = "订单状态 0:待评价 1已评价" )
    public ServerResponseEntity<IPage<MyOrderItemDto>> myOrderItemsComment(@RequestParam(value = "commStatus") Integer commStatus,
                                                                     PageParam<MyOrderItemDto> page) {
        String userId = SecurityUtils.getUser().getUserId();
        IPage<MyOrderItemDto> myOrderDtoIpage = myOrderService.myOrderItemsComment(page, userId, commStatus);
        return ServerResponseEntity.success(myOrderDtoIpage);
    }

    @PutMapping("/cancel/{orderNumber}")
    @Operation(summary = "根据订单编号取消订单" , description = "根据订单编号取消订单")
    @Parameter(name = "orderNumber", description = "订单编号" , required = true)
    public ServerResponseEntity<String> cancel(@PathVariable("orderNumber") String orderNumber) {
        String userId = SecurityUtils.getUser().getUserId();
        Order order = orderService.getOrderByOrderNumberAndUserId(orderNumber, userId, true);
        if (!Objects.equals(order.getStatus(), OrderStatus.UNPAY.value())) {
            // 订单已支付，无法取消订单
            throw new YamiShopBindException("yami.order.status.change");
        }

        List<OrderItem> orderItems = orderItemService.getOrderItemsByOrderNumber(orderNumber,false);
        order.setOrderItems(orderItems);
        // 取消订单
        orderService.cancelOrders(Collections.singletonList(order));
        // 清除缓存
        for (OrderItem orderItem : orderItems) {
            productService.removeProdCacheByProdId(orderItem.getProdId());
            skuService.removeSkuCacheBySkuId(orderItem.getSkuId(), orderItem.getProdId());
        }
        return ServerResponseEntity.success();
    }

    @PutMapping("/receipt/{orderNumber}")
    @Operation(summary = "根据订单号确认收货" , description = "根据订单号确认收货")
    @Parameter(name = "orderNumber", description = "订单编号" , required = true)
    public ServerResponseEntity<String> receipt(@PathVariable("orderNumber") String orderNumber) {
        String userId = SecurityUtils.getUser().getUserId();
        Order order = orderService.getOrderByOrderNumberAndUserId(orderNumber, userId, true);

        if (!Objects.equals(order.getStatus(), OrderStatus.CONSIGNMENT.value())) {
            // 订单不处于待收货状态，无法确认收货
            throw new YamiShopBindException("yami.order.no.delivery");
        }
        if (Objects.equals(order.getRefundStatus(), RefundStatusEnum.APPLY.value())) {
            // 订单退款中，无法确认收货
            throw new YamiShopBindException("yami.order.receipt.refund");
        }
        List<OrderItem> orderItems = orderItemService.getOrderItemsByOrderNumber(orderNumber,true);
        order.setOrderItems(orderItems);
        // 确认收货
        orderService.receiptOrder(Collections.singletonList(order));

        for (OrderItem orderItem : orderItems) {
            productService.removeProdCacheByProdId(orderItem.getProdId());
            skuService.removeSkuCacheBySkuId(orderItem.getSkuId(), orderItem.getProdId());
        }
        return ServerResponseEntity.success();
    }

    @DeleteMapping("/{orderNumber}")
    @Operation(summary = "根据订单号删除订单" , description = "根据订单号删除订单")
    @Parameter(name = "orderNumber", description = "订单号" , required = true)
    public ServerResponseEntity<String> delete(@PathVariable("orderNumber") String orderNumber) {
        String userId = SecurityUtils.getUser().getUserId();
        Order order = orderService.getOrderByOrderNumberAndUserId(orderNumber, userId, true);
        if (!Objects.equals(order.getStatus(), OrderStatus.SUCCESS.value()) && !Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) {
            // 订单未完成或未关闭，无法删除订单
            throw new YamiShopBindException("yami.order.no.success");
        }
        if(order.getRefundStatus() != null && order.getRefundStatus().equals(RefundStatusEnum.APPLY.value())){
            logger.info("订单申请退款中，无法删除订单");
            // 订单退款中，无法删除订单
            throw new YamiShopBindException("yami.order.no.success");
        }
        // 删除订单
        orderService.deleteOrders(Collections.singletonList(order));
        // 删除成功
        return ServerResponseEntity.success(I18nMessage.getMessage("yami.delete.successfully"));
    }

    @GetMapping("/getOrderStatus")
    @Operation(summary = "根据订单编号获取订单状态")
    public ServerResponseEntity<OrderShopDto> getOrderStatus(@RequestParam("orderNumber") String orderNumber) {
        List<String> orderNumberList = Arrays.asList(orderNumber.split(StrUtil.COMMA));
        List<Order> orderList = orderService.getOrdersStatus(orderNumberList);
        Order order = orderList.stream().filter(item -> Objects.equals(item.getOrderMold(), 0)).toList().get(0);
        OrderShopDto orderShopDto = new OrderShopDto();
        orderShopDto.setStatus(order.getStatus());
        orderShopDto.setRefundStatus(order.getRefundStatus());
        // 如果是虚拟商品订单，处理下虚拟商品订单相关数据
        if(Objects.equals(order.getOrderMold(),1)) {
            Long stationId = SecurityUtils.getUser().getStationId();
            orderShopDto.setOrderMold(order.getOrderMold());
            // 虚拟商品留言信息
            orderShopDto.setVirtualRemark(order.getVirtualRemark());
            orderShopDto.setWriteOffStart(order.getWriteOffStart());
            orderShopDto.setWriteOffEnd(order.getWriteOffEnd());
            orderShopDto.setWriteOffNum(order.getWriteOffNum());
            orderShopDto.setWriteOffMultipleCount(order.getWriteOffMultipleCount());
            handlerVirtualProdOrder(orderShopDto, order.getIsRefund(), order.getStatus(), order.getOrderNumber(), stationId);
        }
        return ServerResponseEntity.success(orderShopDto);
    }

    /**
     * 判断是否开启了小程序发货信息管理
     */
    @GetMapping("/checkTradeManaged/{orderNumber}")
    @Operation(summary = "判断是否小程序下单并且开启了小程序发货信息管理", description = "判断是否小程序下单并且开启了小程序发货信息管理")
    public ServerResponseEntity<OrderWxDeliveryVO> checkTradeManaged(@PathVariable("orderNumber") String orderNumber) {
        OrderWxDeliveryVO orderWxDeliveryVO = new OrderWxDeliveryVO();
        // 查询小程序是否已开通发货信息管理服务
        Boolean managed = wxConfig.getTradeManaged();
        if (managed) {
            logger.info("开通判断是不是小程序支付的订单");
            PayInfo payInfo = payInfoService.getOne(new LambdaQueryWrapper<PayInfo>()
                    .eq(PayInfo::getPayStatus, PayStatus.PAYED.value())
                    .eq(PayInfo::getPayEntry, PayEntry.ORDER.value())
                    .like(PayInfo::getOrderNumbers, orderNumber)
                    .orderByDesc(PayInfo::getCreateTime)
                    .last("limit 1"));
            if (Objects.nonNull(payInfo) && Objects.equals(payInfo.getPayType(), PayType.WECHATPAY.value()) && Objects.equals(payInfo.getSystemType(), FlowSystemTypeEnum.APPLETS.value())) {
                Integer orderStatus = wxConfig.getOrderStatusByBizPayNo(payInfo.getBizPayNo());
                if (orderStatus != 0) {
                    orderWxDeliveryVO.setOrderStatus(orderStatus);
                    orderWxDeliveryVO.setBizPayNo(payInfo.getBizPayNo());
                }
            }
        }
        return ServerResponseEntity.success(orderWxDeliveryVO);
    }

    /**
     * 插入订单项、退款和虚拟商品的数据
     * @param orderShopDto
     * @param stationId
     */
    private void refundAndVirtualInfo(OrderShopDto orderShopDto, Long stationId) {
        // 查询商品的信息，用于获取商品秒杀id
        // 查询第一个商品是否为秒杀商品
        if (Objects.equals(orderShopDto.getOrderType(), OrderType.SECKILL.value())) {
            Product product = productService.getById(orderShopDto.getOrderItemDtos().get(0).getProdId());
            orderShopDto.setSeckillId(product.getActivityId());
        }

        // 查询订单退款信息
        List<Integer> returnMoneyStsList = new ArrayList<>();
        returnMoneyStsList.add(ReturnMoneyStsType.FAIL.value());
        returnMoneyStsList.add(ReturnMoneyStsType.CANCEL.value());
        returnMoneyStsList.add(ReturnMoneyStsType.REJECT.value());
        List<OrderRefund> orderRefunds = orderRefundService.list(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getOrderId, orderShopDto.getOrderId())
                .notIn(OrderRefund::getReturnMoneySts, returnMoneyStsList)
                .notIn(OrderRefund::getPlatformInterventionStatus, PlatformInterventionStatus.APPLY.value())
        );
        // 查询是否有申请平台介入退款信息
        List<OrderRefund> orderRefundList = orderRefundService.list(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getOrderId, orderShopDto.getOrderId())
                .eq(OrderRefund::getPlatformInterventionStatus, PlatformInterventionStatus.APPLY.value()));
        Map<Long, List<OrderRefund>> refundMap = orderRefunds.stream().collect(Collectors.groupingBy(OrderRefund::getOrderId));
        Map<Long, List<OrderRefund>> refundListMap = orderRefundList.stream().collect(Collectors.groupingBy(OrderRefund::getOrderId));

        Order order = new Order();
        order.setStatus(orderShopDto.getStatus());
        order.setFinallyTime(orderShopDto.getFinallyTime());
        double alreadyRefundAmount = 0.0;
        // 可以退款的状态(订单已支付，且未关闭)，并在退款时间内
        if (orderShopDto.getStatus() > OrderStatus.UNPAY.value() && orderShopDto.getStatus() < OrderStatus.CLOSE.value()
                && orderRefundService.checkRefundDate(order)) {
            orderShopDto.setCanRefund(true);
            // 有没有正在退款中的订单
            if (CollectionUtil.isEmpty(orderRefunds)) {
                orderShopDto.setCanAllRefund(true);
            }
        }
        if (refundMap.containsKey(orderShopDto.getOrderId())) {
            alreadyRefundAmount = handleOrderRefundInfo(refundMap.get(orderShopDto.getOrderId()), orderShopDto);
        }
        if (refundListMap.containsKey(orderShopDto.getOrderId())) {
            alreadyRefundAmount = handleOrderRefundInfo(refundListMap.get(orderShopDto.getOrderId()), orderShopDto);
        }
        orderShopDto.setCanRefundAmount(Arith.sub(orderShopDto.getActualTotal(), alreadyRefundAmount));

        // 虚拟商品数据处理
        if(Objects.equals(orderShopDto.getOrderMold(),1)) {
            this.handlerVirtualProdOrder(orderShopDto, orderShopDto.getIsRefund(), orderShopDto.getStatus(), orderShopDto.getOrderNumber(), stationId);
        }

    }

    private double handleOrderRefundInfo(List<OrderRefund> orderRefunds, OrderShopDto orderShopDto) {
        double alreadyRefundAmount = 0D;
        for (OrderRefund orderRefund : orderRefunds) {
            alreadyRefundAmount = Arith.add(alreadyRefundAmount, orderRefund.getRefundAmount());
            // 整单退款
            if (Objects.equals(RefundType.ALL.value(), orderRefund.getRefundType())) {
                orderShopDto.setCanRefund(false);
                // 统一的退款单号
                for (OrderItemDto orderItemDto : orderShopDto.getOrderItemDtos()) {
                    orderItemDto.setRefundSn(orderRefund.getRefundSn());
                }
                break;
            }
            // 单项退款，每个单号都不一样
            for (OrderItemDto orderItemDto : orderShopDto.getOrderItemDtos()) {
                if (Objects.equals(orderItemDto.getOrderItemId(), orderRefund.getOrderItemId())) {
                    orderItemDto.setRefundSn(orderRefund.getRefundSn());
                }
            }
        }
        return alreadyRefundAmount;
    }


    /**
     * 添加下虚拟商品的信息
     *
     * @param orderShopDto 用于前端展示的订单信息
     * @param isRefund
     * @param status
     * @param orderNumber
     * @param stationId 门店id
     */
    private void handlerVirtualProdOrder(OrderShopDto orderShopDto, Integer isRefund, Integer status, String orderNumber,Long stationId) {
        if (Objects.equals(isRefund, 0)) {
            orderShopDto.setCanAllRefund(false);
            orderShopDto.setCanRefund(false);
        }
        boolean flag = Objects.equals(status, OrderStatus.WAIT_GROUP.value()) || Objects.equals(status, OrderStatus.UNPAY.value()) ;
        if (flag) {
            return;
        }
        // 卡券信息
        List<OrderVirtualInfo> virtualInfoList = orderVirtualInfoService.list(new LambdaQueryWrapper<OrderVirtualInfo>()
                .eq(OrderVirtualInfo::getOrderNumber, orderNumber)
                .eq(Objects.nonNull(stationId), OrderVirtualInfo::getIsWriteOff, 1)
                .eq(Objects.nonNull(stationId), OrderVirtualInfo::getStationId, stationId));
        if (CollectionUtil.isNotEmpty(virtualInfoList)) {
            orderShopDto.setVirtualInfoList(virtualInfoList);
            orderShopDto.setTotalNum(virtualInfoList.size());
        }
    }

}
